import type {App} from 'vue'
import type {Composer, I18n} from 'vue-i18n'
import {createI18n} from 'vue-i18n'
import {isEmpty, uniq} from 'lodash-es'
import {useWebConfigStore} from '@/stores/modules/webConfig.store'
import type {RouteLocationNormalized} from 'vue-router'
import langMap from '@/lang/util/langMap'
import router from '@/router'
/**
 * 默认只引入 element-plus 的中英文语言包
 * 其他语言包请自行在此 import,并添加到 assignLocale 内
 * 动态 import 只支持相对路径，所以无法按需 import element-plus 的语言包
 * 但i18n的 messages 内是按需载入的
 */
import zhCN from 'element-plus/es/locale/lang/zh-cn'
import en from 'element-plus/es/locale/lang/en'

export let i18n: {
	global: Composer
}

/**
 * element-plus语言包
 */
const assignLocale: AnyObject = {
	'zh-cn': [zhCN],
	en: [en]
}

/**
 * 传入app则初始化i18n，仅页面刷新后执行一次<br/>
 * 否则动态切换语言
 * @param locale
 * @param app
 */
export function loadLang(locale: string, app?: App) {
	const webConfigStore = useWebConfigStore()
	// 加载全局语言包
	const langGlobal = import.meta.glob('./*.ts', {eager: true})
	const globalMessage = (<{ default: AnyObject<string> }>langGlobal[`./${locale}.ts`]).default ?? {}
	// 准备按需加载语言包文件的句柄，在路由守卫中进行按需加载
	if (locale === 'zh-cn') {
		window.loadLangHandle = {
			...import.meta.glob('./zh-cn/**/*.ts'),
			...import.meta.glob('./zh-cn.ts')
		}
	} else {
		window.loadLangHandle = {
			...import.meta.glob('./en/**/*.ts'),
			...import.meta.glob('./en.ts')
		}
	}
	// 语言包
	const messages = {
		[locale]: {...globalMessage}
	}
	// 合并element-plus语言包
	Object.assign(messages[locale], ...assignLocale[locale])
	// 初始化i18n
	if (app) {
		i18n = createI18n({
			// 关闭警告
			missingWarn: false,
			fallbackWarn: false,
			locale: locale,
			// 组合式api
			legacy: false,
			// 挂载$t,$d等到全局
			globalInjection: true,
			fallbackLocale: webConfigStore.lang.fallbackLang,
			messages
		})
		app.use(<I18n>i18n)
	}
	// 动态切换语言
	else {
		// 更新配置
		webConfigStore.lang.defaultLang = locale
		webConfigStore.lang.fallbackLang = locale
		i18n.global.locale.value = locale
		i18n.global.fallbackLocale.value = locale
		// 删除现有的语言包
		for (const key in i18n.global.messages.value) {
			delete (<AnyObject>i18n.global.messages.value)[key]
		}
		i18n.global.setLocaleMessage(locale, messages[locale])
		// 加载动态语言包
		loadDynamicLang(router.currentRoute.value.path)
	}
	return i18n
}

/**
 * 根据path动态加载语言包
 * @param path
 */
export const loadDynamicLang = (path: RouteLocationNormalized['path']) => {
	let loadPath: string[] = []
	const webConfigStore = useWebConfigStore()
	if (path in langMap) {
		loadPath.push(...langMap[path as keyof typeof langMap])
	}
	const prefix = './' + webConfigStore.lang.defaultLang
	// 根据路由 path 加载语言包
	if (path !== '/') {
		loadPath.push(prefix + path + '.ts')
	}
	if (!window.loadLangHandle.publicMessageLoaded) {
		window.loadLangHandle.publicMessageLoaded = []
	}
	const publicMessagePath = prefix + '.ts'
	if (!window.loadLangHandle.publicMessageLoaded.includes(publicMessagePath)) {
		loadPath.push(publicMessagePath)
		window.loadLangHandle.publicMessageLoaded.push(publicMessagePath)
	}
	// 去重
	loadPath = uniq(loadPath)
	for (const key in loadPath) {
		loadPath[key] = loadPath[key].replaceAll('${locale}', webConfigStore.lang.defaultLang)
		if (loadPath[key] in window.loadLangHandle) {
			window.loadLangHandle[loadPath[key]]().then((res: { default: AnyObject }) => {
				const pathName = loadPath[key].slice(loadPath[key].lastIndexOf(prefix) + (prefix.length + 1), loadPath[key].lastIndexOf('.'))
				mergeMessage(res.default, pathName)
			})
		}
	}
}

function getLangFileMessage(mList: any, locale: string) {
	let msg: AnyObject = {}
	locale = '/' + locale
	for (const path in mList) {
		if (mList[path].default) {
			//  获取文件名
			const pathName = path.slice(path.lastIndexOf(locale) + (locale.length + 1), path.lastIndexOf('.'))
			if (pathName.indexOf('/') > 0) {
				msg = handleMsgList(msg, mList[path].default, pathName)
			} else {
				msg[pathName] = mList[path].default
			}
		}
	}
	return msg
}

export function mergeMessage(message: AnyObject, pathName = '') {
	if (isEmpty(message)) return
	if (!pathName) {
		i18n.global.mergeLocaleMessage(i18n.global.locale.value, message)
		return
	}
	let msg: AnyObject = {}
	if (pathName.indexOf('/') > 0) {
		msg = handleMsgList(msg, message, pathName)
	} else {
		msg[pathName] = message
	}
	i18n.global.mergeLocaleMessage(i18n.global.locale.value, msg)
}

export function handleMsgList(msg: AnyObject, mList: AnyObject, pathName: string) {
	const pathNameTmp = pathName.split('/')
	let obj: AnyObject = {}
	for (let i = pathNameTmp.length - 1; i >= 0; i--) {
		if (i == pathNameTmp.length - 1) {
			obj = {
				[pathNameTmp[i]]: mList
			}
		} else {
			obj = {
				[pathNameTmp[i]]: obj
			}
		}
	}
	return mergeMsg(msg, obj)
}

export function mergeMsg(msg: AnyObject, obj: AnyObject) {
	for (const key in obj) {
		if (typeof msg[key] == 'undefined') {
			msg[key] = obj[key]
		} else if (typeof msg[key] == 'object') {
			msg[key] = mergeMsg(msg[key], obj[key])
		}
	}
	return msg
}
